﻿Imports System.IO
Imports System.Text


'[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
' Author: Luke Osborne
' Purpose: Keeps USB HDD's and mapped network shares from going to sleep.
' Main target is Laptops/Portables. 
'
'[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]

Public Class xSleep
    '[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
    ' Application settings
    '[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]

    'Aptly named generic error message. Not much to go wrong with only two buttons. 
    'Either your drive is unplugged, or your path no longer exists.
    Private cntErrorMsg As String = My.Settings.xSleepErr
    'Name of file to be written. Default of xSleepKeepAlive.
    Private appFile As String = My.Settings.xSleep
    'Data to be written in file. Default of "DEL this file".
    Private txtFileStr As String = My.Settings.xSleepMsg
    'File extension. Default of ".txt".
    Private appFileExt As String = My.Settings.FileExt.ToString
    'Write path for first drive. Default of "C:\".
    Private appWritePath As String = My.Settings.WritePath.ToString
    'The interval the timer ticks on. Default of 2 minutes.
    Private appMinutes As String = My.Settings.Minutes.ToString
    'If True xSleep will autorun with Windows, and start minimised. 
    'The timer will be enabled.   
    Private appAutorun As String = My.Settings.Autorun
    'If on xSleep will operate for 8 hours. Default is 6AM start. 
    'Timer is disabled on interval tick.
    Private appWorkingDay As Boolean = My.Settings.WorkingDay
    'Override Working day default start. The usual 9am to 5pm grind can be set here.
    Private appWDAlt As Integer = My.Settings.AltTime
    'Feel like changing the text of the Control button? Default is Start.
    Private xStart As String = My.Settings.xStart
    'Feel like changing the text of the Control button? Default is Stop.
    Private xStop As String = My.Settings.xStop
    'Restores the Multi-drive checkbox if previously on.
    Private xMultiDrive As Boolean = My.Settings.xMultiDrive
    'String padding.
    Private xStrPad As String = My.Settings.StrPad
    'xSleeps 8 hour timespan. 
    Private appTS As TimeSpan

    'Why am I here?
    'Private appCurrDir As String = Environment.CurrentDirectory

    'TODO: Generic function, properties and dynamic app resizing with advanced option to add
    'an large number of drives.
    Private xDrive2 As Boolean = My.Settings.xDrive2
    Private xDrive3 As Boolean = My.Settings.xDrive3
    Private xDrive4 As Boolean = My.Settings.XDrive4
    Private xD2WritePath As String = My.Settings.WritePath2
    Private xD3WritePath As String = My.Settings.WritePath3
    Private xD4WritePath As String = My.Settings.WritePath4

    Private strFileInfo As String = (appWritePath & appFile & appFileExt)
    Private appFileInfo As New FileInfo(strFileInfo)

    Private strFileInfoDrive2 As String = (xD2WritePath & appFile & appFileExt)
    Private appFileInfoDrive2 As New FileInfo(strFileInfoDrive2)

    Private strFileInfoDrive3 As String = (xD3WritePath & appFile & appFileExt)
    Private appFileInfoDrive3 As New FileInfo(strFileInfoDrive3)

    Private strFileInfoDrive4 As String = (xD4WritePath & appFile & appFileExt)
    Private appFileInfoDrive4 As New FileInfo(strFileInfoDrive4)

    'Used to locate drives and correctly set drop down list selected indexes.
    'Specifically assits loading saved settings for Drive2, 3, and 4 Comboboxes.
    Private DriveToFind As String
    Private DriveFoundAt As Integer

    'Delegates to System Tray if Autorun is True.
    Public Delegate Sub InvokeDelegate()

    'TEST
    'Public count1

    '[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
    ' Load
    '[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]

    Private Sub xSleep_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'count1 = Environment.TickCount

        'Validates appFileExt and appFile (with IsAlphaNumeric).
        'Calls Directory.Exists for Write path.
        ConfValidate()

        'Restores saved settings for Multi-drive drop downs. 
        'Populates via Environment.LogicalDrives
        PrepDropDowns()

        'If you're an admin user this function cleans up ram, otherwise to bad so sad.
        SetWorkingSet(System.IntPtr.op_Explicit(CInt(750000)), System.IntPtr.op_Explicit(CInt(300000)))

        'Looks for just '/m' at present. Sets Autorun to True.
        GetCommandLineArgs()

        'Loads application in the middle of the screen.
        ScreenPos()

        'Checks autorun status, if True then invokes public delegate to send it to the system tray without user input.
        'Also sends a button click to the Control button (Start).
        If xAR() Then
            Me.BeginInvoke(New InvokeDelegate(AddressOf Me.ToSystemTray))
            ControlButton_Click(Nothing, Nothing)
        End If

        'TEST
        'DebugLabel.Visible = True
        'DebugLabel.Text = (TestTimer(count1) & "s")

    End Sub


    '[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
    ' Buttons
    '[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]

    Private Sub FolderButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles FolderButton.Click
        Dim xstrSleepFolder As String

        'Show folder dialog window.
        xSleepFolderBD1.ShowDialog()

        'How you can choose a zero length folder name I do not know.
        If Not xSleepFolderBD1.SelectedPath.Length = 0 Then
            'Enable Start button, get selected path, show it, and save it to xSleep settings.
            ControlButton.Enabled = True
            xstrSleepFolder = Strings.Left$(xSleepFolderBD1.SelectedPath.ToString(), 15)
            PathLabel.Text = xstrSleepFolder & xStrPad
            PathLabel.Visible = True
            ChangePath(xSleepFolderBD1.SelectedPath.ToString)
        End If
    End Sub

    Private Sub ControlButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ControlButton.Click
        'Don't be silly and try set zero for a time interval.
        If xSleepUpDown.Value > 0 Then
            Dim xMintoSec As Integer
            'Save interval to application settings.
            ChangeInterval(xSleepUpDown.Value)
            'Convert minutes to miliseconds
            xMintoSec = appMinutes * 60000
            'Timers like miliseconds
            xSleepTimer.Interval = xMintoSec

            'Toggle button text, start and stop timer.
            If ControlButton.Text = xStop Then
                ControlButton.ForeColor = Color.Green
                ControlButton.Text = xStart
                xSleepTimer.Enabled = False
                FolderButton.Enabled = True
            Else
                ControlButton.ForeColor = Color.Red
                ControlButton.Text = xStop
                xSleepTimer.Enabled = True
                FolderButton.Enabled = False
            End If

        Else
            'Display aptly named error message.
            MsgBox(cntErrorMsg)
        End If

    End Sub

    '[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
    ' Timer
    '[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]

    Private Function xSleepTimer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles xSleepTimer.Tick
        'Get the current time of day, in 24 hour format.
        appTS = Date.Now.TimeOfDay
        'We really only care about our 8 hour timer.
        Dim Hours As Integer

        'If True then the Control button has been clicked outside working hours.
        If appTS.Hours < xWDAlt() Then
            'Set hours elapsed to 8.
            Hours = 8
        Else
            'Now we now we are running inside our 8 hour timer.
            Hours = appTS.Hours - xWDAlt()
        End If

        'If Working day is enabled and more than 8 hours have passed, Stop.
        If xWD() And Hours >= 8 Then
            ControlButton_Click(Nothing, Nothing)
            'Out of the function.
            Return True
        End If

        'Else begin writing to all active drives.
        'Each one in it's own block, as the odd's of any given drive being 
        'removed from the system is high.
        Try
            WriteKeepAlive(txtFileStr, appFileInfo.ToString)
        Catch ex As Exception
            ReadWriteError()
        End Try

        Try
            appFileInfo.Delete()
        Catch ex As Exception
            ReadWriteError()
        End Try

        If Drive2 Then
            Try
                WriteKeepAlive(txtFileStr, appFileInfoDrive2.ToString)
                appFileInfoDrive2.Delete()
            Catch ex As Exception
                ReadWriteError()
            End Try

        End If

        If Drive3 Then
            Try
                WriteKeepAlive(txtFileStr, appFileInfoDrive3.ToString)
                appFileInfoDrive3.Delete()
            Catch ex As Exception
                ReadWriteError()
            End Try

        End If

        If Drive4 Then
            Try
                WriteKeepAlive(txtFileStr, appFileInfoDrive4.ToString)
                appFileInfoDrive4.Delete()
            Catch ex As Exception
                ReadWriteError()
            End Try

        End If
        'All done, wait for next timer tick.
        Return True
    End Function

    '[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
    ' Misc
    '[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]

    'Delegate to System tray.
    Private Sub ToSystemTray()
        Me.Visible = False
        'xSleepNotifyIcon to show an icon on system tray
        Me.XSleepNotifyIcon.Visible = True
    End Sub

    'Could check the name of the executable here, it's arg zero.
    Sub GetCommandLineArgs()
        ' Display arguments passed to the application via the command line.
        Dim args = Environment.GetCommandLineArgs()
        Dim s As String

        'Only looks for the switch '/m' currently.
        For Each s In args
            If s = "/m" Then xAR() = True
        Next

        'Clear variables.
        args = Nothing
        s = Nothing
    End Sub

    Sub ChangePath(ByVal thePath As String)
        'Handles changes the first drives path. 
        Dim strLen As Integer
        Dim theDiff As Integer
        Dim thePos As Integer

        strLen = thePath.Length
        thePos = thePath.IndexOf("\")
        theDiff = strLen - thePos

        'VB's folder browsing dialog appens a slash to root drives, eg C:\ but not to C:\temp
        If Not theDiff = 1 Then thePath = thePath & "\"

        'Update application settings for the next load.
        My.Settings.WritePath = thePath
        appWritePath = thePath

        'Clear variables.
        strLen = Nothing
        theDiff = Nothing
        thePos = Nothing

    End Sub

    Sub ChangeInterval(ByVal theTime As String)
        'From Up/Down numeric box. Stored for the next time the application loads.
        My.Settings.Minutes = theTime
        appMinutes = theTime
    End Sub

    Private Sub xSleep_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        Try
            'Just in case
            appFileInfo.Delete()
            appFileInfoDrive2.Delete()
            appFileInfoDrive3.Delete()
            appFileInfoDrive4.Delete()
        Catch ex As Exception
            'Nothing to see here
        End Try
    End Sub

    Private Sub xSleep_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize
        Select Case Me.WindowState
            Case FormWindowState.Maximized
                'Maximised
            Case FormWindowState.Minimized
                'Minimise
                Me.Hide()
            Case FormWindowState.Normal
                'Normal
        End Select
    End Sub

    'Max Interval is 20 minutes. See xWD property. Timer can therefore run upto 8 hours and 20min.
    Private Sub xSleepUpDown_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles xSleepUpDown.ValueChanged
        If ControlButton.Text = xStop Then ControlButton_Click(Nothing, Nothing)
    End Sub

    '[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
    ' Menus
    '[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]

    Private Sub XSleepNotifyIcon_MouseDoubleClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles XSleepNotifyIcon.MouseDoubleClick
        'Handles the icon in the system tray area, same as the context menu Show option, but activated on a double click of the icon.
        Me.Show()
        Me.Visible = True
        Me.WindowState = FormWindowState.Normal
        Me.Activate()
        Me.Focus()


    End Sub

    Private Sub XSleepNotifyIcon_MouseSingleClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles XSleepNotifyIcon.MouseDoubleClick
        'NotifyIcon1.Visible = False
        'Me.ShowInTaskbar = True
        Me.BringToFront()

        'Handler here for a single click that does nothing
    End Sub

    Private Sub ExitToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ExitToolStripMenuItem.Click
        Me.Close()
    End Sub

    Private Sub AboutToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AboutToolStripMenuItem.Click
        xSleepAbout.Show()
    End Sub

    Private Sub ExitToolStripMenuItem1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ExitToolStripMenuItem1.Click
        Me.Close()
    End Sub

    Private Sub ShowToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ShowToolStripMenuItem.Click
        Me.Show()
        Me.BringToFront()
        Me.Visible = True
        Me.WindowState = FormWindowState.Normal
    End Sub

    Private Sub OptionsToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OptionsToolStripMenuItem.Click
        'Stop timer if the Options are opened.
        If ControlButton.Text = xStop Then ControlButton_Click(Nothing, Nothing)
        xSleepOpt.Show()
    End Sub


    '[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
    ' Checkboxes and Comboboxes
    '[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]

    Private Sub MultiDriveCheckBox_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MultiDriveCheckBox.CheckedChanged
        'Toggles all checkboxes on form. Saves to application settings.
        If MultiDriveCheckBox.Checked Then
            MultiDrive = True
            ToggleMultiDrive(xMultiDrive)
        ElseIf MultiDriveCheckBox.Checked = False Then
            MultiDrive = False
            Drive2CheckBox.Checked = False
            Drive3CheckBox.Checked = False
            Drive4CheckBox.Checked = False
            ToggleMultiDrive(xMultiDrive)
        End If

    End Sub

    Sub ToggleMultiDrive(ByVal Toggle As Boolean)
        Drive2CheckBox.Enabled = Toggle
        Drive3CheckBox.Enabled = Toggle
        Drive4CheckBox.Enabled = Toggle
        Drive2ComboBox.Enabled = Toggle
        Drive3ComboBox.Enabled = Toggle
        Drive4ComboBox.Enabled = Toggle
    End Sub

    Private Sub Drive2CheckBox_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Drive2CheckBox.CheckedChanged
        'Toggles Drive 2's status, saves to application settings.
        If Drive2CheckBox.Checked Then
            Drive2 = True
            Drive2ComboBox.Visible = True
        ElseIf Drive2CheckBox.Checked = False Then
            Drive2 = False
            Drive2ComboBox.Visible = False
        End If

    End Sub

    Private Sub Drive3CheckBox_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Drive3CheckBox.CheckedChanged
        'Toggles Drive 3's status, saves to application settings.
        If Drive3CheckBox.Checked Then
            Drive3 = True
            Drive3ComboBox.Visible = True
        ElseIf Drive3CheckBox.Checked = False Then
            Drive3 = False
            Drive3ComboBox.Visible = False
        End If

    End Sub

    Private Sub Drive4CheckBox_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Drive4CheckBox.CheckedChanged
        'Toggles Drive 4's status, saves to application settings.
        If Drive4CheckBox.Checked Then
            Drive4 = True
            Drive4ComboBox.Visible = True
        ElseIf Drive4CheckBox.Checked = False Then
            Drive4 = False
            Drive4ComboBox.Visible = False
        End If

    End Sub

    'Following three ComboBox sub's fire on selected index changing. 
    'They check the other two ComboBoxes values, if they match their own value then the Control button is disabled. 
    'This prevents writing to the same drive twice. Not entirely bullet proof. 
    'Writing to the same drive twice isn't harmful to the drive (other than wear and tear) or xSleep, it's just pointless

    'Drive Two
    Private Sub Drive2ComboBox_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Drive2ComboBox.SelectedIndexChanged

        If Not Drive2ComboBox.SelectedIndex = 0 Then
            ControlButton.Enabled = True
            If Combobox_Same_Selected(2) Then
                ControlButton.Enabled = False
            End If
            Drive2Path = Drive2ComboBox.Text
            strFileDrive2 = Drive2Path
        ElseIf Drive2ComboBox.SelectedIndex = 0 Then
            ControlButton.Enabled = False
        End If

    End Sub

    'Drive Three
    Private Sub Drive3ComboBox_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Drive3ComboBox.SelectedIndexChanged
        If Not Drive3ComboBox.SelectedIndex = 0 Then
            ControlButton.Enabled = True
            If Combobox_Same_Selected(3) Then
                ControlButton.Enabled = False
            End If
            Drive3Path = Drive3ComboBox.Text
            strFileDrive3 = Drive3Path
        ElseIf Drive3ComboBox.SelectedIndex = 0 Then
            ControlButton.Enabled = False
        End If

    End Sub

    'Drive Four
    Private Sub Drive4ComboBox_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Drive4ComboBox.SelectedIndexChanged
        If Not Drive4ComboBox.SelectedIndex = 0 Then
            ControlButton.Enabled = True
            If Combobox_Same_Selected(4) Then
                ControlButton.Enabled = False
            End If
            Drive4Path = Drive4ComboBox.Text
            strFileDrive4 = Drive4Path
        ElseIf Drive4ComboBox.SelectedIndex = 0 Then
            ControlButton.Enabled = False
        End If
    End Sub

    Private Function Combobox_Same_Selected(ByVal int As Integer)
        'Some generic strings to work with.
        Dim str As String = vbNullString
        Dim d2 As String = vbNullString
        Dim d3 As String = vbNullString
        Dim d4 As String = vbNullString

        'Wonderful Try/Catch blocks just in case the the ComboBox isn't visible.
        'Tested as faster than checking if ComboBox.Visible property via an If/Else.
        Try
            d2 = Drive2ComboBox.SelectedItem.ToString
        Catch ex As Exception

            d2 = Nothing
        End Try

        Try
            d3 = Drive3ComboBox.SelectedItem.ToString
        Catch ex As Exception

            d3 = Nothing
        End Try

        Try
            d4 = Drive4ComboBox.SelectedItem.ToString
        Catch ex As Exception
            d4 = Nothing
        End Try

        'Generic three way statement, accepts the integer passed into the function.
        'The integer represents the Comobox making the call. e.g if Combox 2 is check 3 and 4 then
        'the value of int would be 2.

        If int = 2 Then
            str = d2
            d2 = Nothing
        ElseIf int = 3 Then
            str = d3
            d3 = Nothing
        ElseIf int = 4 Then
            str = d4
            d4 = Nothing
        End If

        'No matches found in other Comboboxes, Return True.
        If str = d2 Or str = d3 Or str = d4 And Not str = Nothing Then
            Return True
        End If

        'Match found. Disable Control button.
        Return False

    End Function




    '[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
    ' Properties
    '[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]

    'Only available to the main application. 
    'Rolls the private variables for path, file, and extension into one new Fileinfo object
    'Validates the values appFileExt and appFile (with IsAlphaNumeric).
    'Calls Directory.Exists for Writepath and resets PathLabel and Tooltip on Set.
    Private Property strFile()
        Get
            strFileInfo = (appWritePath & appFile & appFileExt)
            Return strFileInfo
        End Get
        Set(ByVal value)
            ConfValidate()
            appFileInfo = New IO.FileInfo(strFileInfo)
        End Set
    End Property

    'One change on the multi-drive properties is they do not call Configuration Validate!
    'The drop downs are instead read only, and populated by Environment.Logical drives. 
    Private Property strFileDrive2()
        Get
            strFileInfoDrive2 = (xD2WritePath & appFile & appFileExt)
            Return strFileInfoDrive2
        End Get
        Set(ByVal value)
            'ConfValidate()
            strFileInfoDrive2 = (value & appFile & appFileExt)
            appFileInfoDrive2 = New IO.FileInfo(strFileInfoDrive2)
        End Set
    End Property

    'Tiger
    Private Property strFileDrive3()
        Get
            strFileInfoDrive3 = (xD3WritePath & appFile & appFileExt)
            Return strFileInfoDrive3
        End Get
        Set(ByVal value)
            'ConfValidate()
            strFileInfoDrive3 = (value & appFile & appFileExt)
            appFileInfoDrive3 = New IO.FileInfo(strFileInfoDrive3)
        End Set
    End Property

    'Elepahnt
    Private Property strFileDrive4()
        Get
            strFileInfoDrive4 = (xD4WritePath & appFile & appFileExt)
            Return strFileInfoDrive4
        End Get
        Set(ByVal value)
            'ConfValidate()
            strFileInfoDrive4 = (value & appFile & appFileExt)
            appFileInfoDrive4 = New IO.FileInfo(strFileInfoDrive4)
        End Set
    End Property

    'Used on application load. Get re-checks the Multi-drive checkbox.
    'Set takes the current boolean value of the Multi-drive checkbox.
    Private Property MultiDrive() As Boolean
        Get
            If xMultiDrive = True Or xMultiDrive = False Then
                Return My.Settings.xMultiDrive
            Else
                Return False
            End If
        End Get
        Set(ByVal value As Boolean)
            My.Settings.xMultiDrive = value
            xMultiDrive = My.Settings.xMultiDrive
        End Set
    End Property

    'Used on application load. Get re-checks the first of the Multi-drive boxes so long as Multi-drive itself is checked.
    'Set takes the current boolean value of the first Multi-drive checkbox
    Private Property Drive2() As Boolean
        Get
            If xDrive2 = True Or xDrive2 = False Then
                Return My.Settings.xDrive2
            Else
                Return False
            End If
        End Get
        Set(ByVal value As Boolean)
            My.Settings.xDrive2 = value
            xDrive2 = My.Settings.xDrive2
        End Set
    End Property

    'Tiger
    Private Property Drive3() As Boolean
        Get
            If xDrive3 = True Or xDrive3 = False Then
                Return My.Settings.xDrive3
            Else
                Return False
            End If
        End Get
        Set(ByVal value As Boolean)
            My.Settings.xDrive3 = value
            xDrive3 = My.Settings.xDrive3
        End Set
    End Property

    'Elephant
    Private Property Drive4() As Boolean
        Get
            If xDrive4 = True Or xDrive4 = False Then
                Return My.Settings.XDrive4
            Else
                Return False
            End If
        End Get
        Set(ByVal value As Boolean)
            My.Settings.XDrive4 = value
            xDrive4 = My.Settings.XDrive4
        End Set
    End Property

    'Get checks the directory to be written to exists on this machine, then returns the value.
    'Set checks the new directory selected exists first, else it defaults back to C:\. 
    'If you don't have a C:\ drive then you should be thankful for the Try/Catch in the timer tick function.
    Private Property Drive2Path()
        Get
            If Directory.Exists(xD2WritePath) Then
                Return My.Settings.WritePath2
            Else
                Drive2Path = xD2WritePath
                Return My.Settings.WritePath2
            End If
        End Get
        Set(ByVal value)
            If Directory.Exists(value) Then
                My.Settings.WritePath2 = value
                xD2WritePath = My.Settings.WritePath2
            Else
                My.Settings.WritePath2 = "C:\"
                xD2WritePath = My.Settings.WritePath2
            End If

        End Set
    End Property

    'Tiger
    Private Property Drive3Path()
        Get
            If Directory.Exists(xD3WritePath) Then
                Return My.Settings.WritePath3
            Else
                Drive3Path = xD3WritePath
                Return My.Settings.WritePath3
            End If
        End Get
        Set(ByVal value)
            If Directory.Exists(value) Then
                My.Settings.WritePath3 = value
                xD3WritePath = My.Settings.xDrive3
            Else
                My.Settings.WritePath3 = "C:\"
                xD3WritePath = My.Settings.WritePath3
            End If

        End Set
    End Property

    'Elephant
    Private Property Drive4Path()
        Get
            If Directory.Exists(xD4WritePath) Then
                Return My.Settings.WritePath4
            Else
                Drive4Path = xD4WritePath
                Return My.Settings.WritePath4
            End If
        End Get
        Set(ByVal value)
            If Directory.Exists(value) Then
                My.Settings.WritePath4 = value
                xD4WritePath = My.Settings.WritePath4
            Else
                My.Settings.WritePath4 = "C:\"
                xD4WritePath = My.Settings.WritePath4
            End If

        End Set
    End Property

    'Public property, lets the xSleep options safely look at the autorun setting.
    'Get returns Autorun Boolean. If True the application will automatically start with Windows.
    'SOFTWARE\Microsoft\Windows\CurrentVersion\Run is the default location.
    'The CMD line switch can be used to toggle this property '/m'
    Public Property xAR() As Boolean
        Get
            appAutorun = My.Settings.Autorun
            Return My.Settings.Autorun
        End Get
        Set(ByVal value As Boolean)
            My.Settings.Autorun = value
            appAutorun = My.Settings.Autorun
        End Set
    End Property

    'Public property, lets the xSleep options safely look at the Working day setting.
    'Get returns a Boolean. If True the working day is a default 8 hour timespan.
    'The timespan defaults to 6 A.M meaning the xSleep application will automatically stop
    'when the system time passes 2 P.M, 
    'Trigged by timer tick function! Accuracy limited to the interval set! 
    Public Property xWD() As Boolean
        Get
            appWorkingDay = My.Settings.WorkingDay
            Return My.Settings.WorkingDay
        End Get
        Set(ByVal value As Boolean)
            My.Settings.WorkingDay = value
            appWorkingDay = My.Settings.WorkingDay
        End Set
    End Property

    'Public property, lets the xSleep options safely look at the Alternate time setting.
    'Set takes it value from the Options numeric up down which is constrained to values between 6 and 10.
    'Change this value to 9 and assuming xWD is True then xSleep will automatically operate between 9am and 5pm.
    'Your hard drives will be allow to sleep outside this timespan.
    Public Property xWDAlt() As Integer
        Get
            appWDAlt = My.Settings.AltTime
            Return My.Settings.AltTime
        End Get
        Set(ByVal value As Integer)
            My.Settings.AltTime = value
            appWDAlt = My.Settings.AltTime
        End Set
    End Property

    '[][][][][][][][][][][][][][][][][][][][][][]
    'ALL FUNCTIONS'
    '[][][][][][][][][][][][][][][][][][][][][][]

    'TODO: Get around to outputting something useful with the Error information.
    'Called by the Timer tick function.
    'Accepts a full path, including filename and the string data to put in the file.
    'Returns True if it can write, and close the file.
    'Returns False if it either fails to write (HDD missing) or fails to close (File in use).
    Private Function WriteKeepAlive(ByVal strData As String, _
      ByVal FullPath As String, _
        Optional ByVal ErrInfo As String = vbNullString) As Boolean

        Dim bAns As Boolean = False
        Dim objReader As StreamWriter
        Try
            objReader = New StreamWriter(FullPath)
            objReader.Write(strData)
            objReader.Close()
            bAns = True
        Catch Ex As Exception
            ErrInfo = Ex.Message
        End Try
        Return bAns
    End Function

    'Used by Configuration validation, checks the filename.
    'Returns a double boolean!
    'First value scans the string for numbers which are allowed.
    'Second value scans for lowercase and uppercase characters A to Z.
    'If special characters are encountered the returned values will be false, and validation will fail.
    Private Function IsAlphaNumeric(ByVal str As String) As Boolean
        Return System.Text.RegularExpressions.Regex.IsMatch(str, "[0-9]+") Or System.Text.RegularExpressions.Regex.IsMatch(str, "[a-zA-Z]+")
    End Function

    'This is the result of failing validation.
    'TODO: Disable Multi-drive, untick boxes, undot i's.
    Private Function ResetPanic()
        My.Settings.WritePath = "c:\"
        appWritePath = My.Settings.WritePath
        My.Settings.FileExt = ".txt"
        appFileExt = My.Settings.FileExt
        My.Settings.xSleep = "xSleepKeepAlive"
        appFile = My.Settings.xSleep
        My.Settings.Minutes = "2"
        appMinutes = My.Settings.Minutes
        strFile = strFile(strFileInfo)
        PathLabel.Text = "c:\"
        xSleepUpDown.Value = appMinutes
        ControlButton.Enabled = False
        Return True
    End Function

    'Configuration validation.
    'Makes sure our default settings loaded are ok.
    Private Function ConfValidate()
        Dim chkFileExt As Boolean = False
        Dim chkIsAlphaNum As Boolean = False


        If appFileExt.ToString.IndexOf(".") = 0 And IsAlphaNumeric(appFile) = True Then
            chkFileExt = True
            chkIsAlphaNum = True
        End If

        If chkFileExt = True And appFileExt.Length < 5 _
        And appFile.Length < 31 And IsAlphaNumeric(appFile) = True And _
        Directory.Exists(appWritePath) Then
            'We are ok.
            PathLabel.Text = appWritePath
            xSleepUpDown.Value = appMinutes

        Else
            'Panic
            ResetPanic()
            MsgBox(cntErrorMsg)
        End If

        PathLabel.Text = Strings.Left$(PathLabel.Text, 15) & xStrPad
        xSleepToolTip.SetToolTip(PathLabel, appWritePath.ToString)

        Return True
    End Function

    'Saves validating the three dropdown lists for Multi-drives.
    'Gets the stored string and searchs the Dropdown lists until it finds a match.
    Private Function FindWord(ByVal w As String) As Boolean

        DriveFoundAt += 1
        If w.Contains(DriveToFind) Then
            Return True
        Else
            Return False
        End If

    End Function

    'Saves validating the three dropdown lists for Multi-drives.
    'The extra work of finding drives and setting selected indexes is done here.
    'Used on application load to restore previously selected Multi-drive selections.
    'False here will trigger an unchecking of the Multi-drive combobox. 
    'Usually means the USB drive has been removed and not plugged back in.
    Private Function DriveFinder(ByVal findstr As String, ByVal delimitedtxt As String)
        Dim arr() As String
        Dim a As String = delimitedtxt
        arr = a.Split(",")

        'using Find
        DriveToFind = findstr
        DriveFoundAt = -1    'not found
        If Not Array.Find(arr, AddressOf FindWord) Is Nothing Then
            'MessageBox.Show("Found at: " + DriveFoundAt.ToString)
        Else
            'MessageBox.Show("Not found")
        End If
        Return DriveFoundAt.ToString
    End Function


    'Populate drop downs. Called on application load.
    Private Function PrepDropDowns()
        Dim drives As String() = Environment.GetLogicalDrives()
        Dim drivesString As String = vbNullString
        'drivesString = drivesString.TrimEnd(" "c, ","c)
        For Each drive As String In drives
            'No one likes floppy drives.
            If Not drive = "A:\" Then
                Drive2ComboBox.Items.Add(drive)
                'Drive3ComboBox.Items.Add(drive)
                'Drive4ComboBox.Items.Add(drive)
                drivesString += drive & ", "
            End If
        Next

        'Thanks Dot Net Spider. A much quicker way to populate drop multiple comboboxes with the same data.
        Dim obj As Object() = New Object(Drive2ComboBox.Items.Count - 1) {}
        Drive2ComboBox.Items.CopyTo(obj, 0)
        Drive3ComboBox.Items.AddRange(obj)
        Drive4ComboBox.Items.AddRange(obj)

        'Set Multi-drive to it's saved state on application load.
        MultiDriveCheckBox.Checked = MultiDrive()

        'The following restores the saved state of the Multi-drive checkboxes and comboboxes.
        If MultiDriveCheckBox.Checked = True Then

            Drive2CheckBox.Checked = Drive2()
            If Drive2CheckBox.Checked Then Drive2ComboBox.SelectedIndex = DriveFinder(Drive2Path, drivesString)

            Drive3CheckBox.Checked = Drive3()
            If Drive3CheckBox.Checked Then Drive3ComboBox.SelectedIndex = DriveFinder(Drive3Path, drivesString)

            Drive4CheckBox.Checked = Drive4()
            If Drive4CheckBox.Checked Then Drive4ComboBox.SelectedIndex = DriveFinder(Drive4Path, drivesString)

        End If
        Return True
    End Function

    'Lets be nice and load the application in the middle of the screen.
    'Dragons live here.
    Private Function ScreenPos()
        Try
            Dim intX As Integer = Screen.PrimaryScreen.Bounds.Width
            Dim intY As Integer = Screen.PrimaryScreen.Bounds.Height

            Me.Left = intX * 0.5 - (Me.Width * 0.5)
            Me.Top = intY * 0.5 - (Me.Height * 0.5)
            Return True
        Catch ex As Exception
            'Fail
        End Try
        Return False
    End Function

    'USB drive unplugged mid-flight?
    'Triggers Stop on xSleep.
    Function ReadWriteError()
        ControlButton_Click(Nothing, Nothing)
        MsgBox(cntErrorMsg)
        Return True
    End Function

    'Handy! Set Debug Label visible to true.
    Private Function TestTimer(ByVal count1)
        Dim count2 = Environment.TickCount
        Dim time_elapsed
        time_elapsed = ((count2 - count1) / 1000)
        Return time_elapsed
    End Function 'TestTimer

    '//RAM CLEANUP\\
    Public Sub SetWorkingSet(ByVal lnMaxSize As System.IntPtr, ByVal lnMinSize As System.IntPtr)

        Try
            Dim loProcess As System.Diagnostics.Process = System.Diagnostics.Process.GetCurrentProcess()
            loProcess.MaxWorkingSet = lnMaxSize
            loProcess.MinWorkingSet = lnMinSize

        Catch
            'do nothing. this only works on a machine on which the user has admin rights
        End Try
    End Sub
    '//RAM CLEANUP\



End Class
